package com.stockz.ui.swing.charting.util;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.List;

import com.stockz.core.model.Bar;
import com.stockz.core.util.BarUtil;
import com.stockz.core.util.BarUtil.BarValueType;
import com.stockz.core.util.CoreConstant.TIME_UNIT;
import com.stockz.ui.swing.charting.display.Displayable;
import com.stockz.ui.swing.charting.view.StockChartPanel;
import com.stockz.ui.swing.charting.view.StockChartPanelState;

public class ChangeTimeUnitUtil{

	private static double pointAndFigurePercent = 2.5;
	private static BarValueType pointAndFigureBarValueType = BarValueType.AVGPRICE;
	
	public static void changeTimeUnit(StockChartPanel stockChartPanel) {
			StockChartPanelState state = stockChartPanel.getStockChartPanelState();
			
			TIME_UNIT selectedItem = state.getCurrentTimeUnit();
			
			List<Bar> backupBarList = state.getBackupBarList();
			if(backupBarList != null && !backupBarList.isEmpty()){
				if(TIME_UNIT.DAILY.equals(selectedItem)){
					if(state.getBarList() != null && state.getBackupBarList() != null
							&& state.getBarList().size() == state.getBackupBarList().size()){
						SetStockChartPanelSizeUtil.setStockChartPanelSize(stockChartPanel);
						RepaintStockChartPanelUtil.repaintStockChartPanel(stockChartPanel);
						SetStockChartViewPortUtil.setStockChartViewPort(stockChartPanel);
						return;
					}
					state.getBarList().clear();
					state.getBarList().addAll(backupBarList);
				}else{
					ArrayList<Bar> barList = new ArrayList<Bar>();
					List<Bar> tempList = new ArrayList<Bar>();
					
					Date pivot = nextPivot(
							backupBarList,
							backupBarList.size()-1,
							backupBarList.get(
							backupBarList.size()-1).getDate(),
							selectedItem);
					
					for(int i = backupBarList.size()-1; i >= 0 ; i--){
						Bar bar = backupBarList.get(i);
						
						if(bar.getDate().before(pivot)){
							tempList.add(bar);
						}else{
							Bar b = union(tempList);
							if(b != null){
								barList.add(b);
							}
							tempList.clear();
							tempList.add(bar);
							pivot = nextPivot(backupBarList,i,pivot,selectedItem);
						}
					}
					if(!tempList.isEmpty()){
						barList.add(union(tempList));
					}
					Collections.sort(barList);
					state.getBarList().clear();
					state.getBarList().addAll(barList);
				}
				
				//Recalculate indicators
				for(Displayable indicatorDisplay : stockChartPanel
						.getStockChartPanelState().getDisplayableSet()){
						indicatorDisplay.refreshValues();
				}
				
				SetStockChartPanelSizeUtil.setStockChartPanelSize(stockChartPanel);
				RepaintStockChartPanelUtil.repaintStockChartPanel(stockChartPanel);
				SetStockChartViewPortUtil.setStockChartViewPort(stockChartPanel);
			}
	}
	
	private static Date nextPivot(List<Bar> barList,int index,Date date, TIME_UNIT unit){
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);
		switch(unit){
		case DAILY : calendar.add(Calendar.DATE, 1);break;
		case WEEKLY : 
			if(calendar.getFirstDayOfWeek() == calendar.get(Calendar.DAY_OF_WEEK)){
				calendar.add(Calendar.DATE, 7);
			}
			while(calendar.getFirstDayOfWeek() != calendar.get(Calendar.DAY_OF_WEEK)){
				calendar.add(Calendar.DATE, 1);
			}
			break;
		case MONTHLY : 
			calendar.set(Calendar.DATE, 1);
			calendar.add(Calendar.MONTH, 1);
			break;
		case QUARTERLY : 
			calendar.add(Calendar.MONTH, 3-calendar.get(Calendar.MONTH)%3);
			calendar.set(Calendar.DATE, 1);
			break;
		case YEARLY : 
			calendar.set(Calendar.DATE, 1);
			calendar.set(Calendar.MONTH, Calendar.JANUARY);
			calendar.add(Calendar.YEAR, 1);
			break;
		case POINT_AND_FIGURE :
			double value = BarUtil.getValue(barList.get(index),pointAndFigureBarValueType);
			double high = value + (pointAndFigurePercent*value/100);
			double low = value - (pointAndFigurePercent*value/100);
			for(int i = index; i >= 0; i--){
				double v = BarUtil.getValue(barList.get(i),pointAndFigureBarValueType);
				if(v < low || v > high){
					return barList.get(i).getDate();
				}
			}
			return barList.get(0).getDate();
		}
		
		return calendar.getTime();
	}
	
	private static Bar union(List<Bar> barList){
		Bar b = null;
		if(barList != null && !barList.isEmpty()){
			b = new Bar();
			double high = 0;
			double low = Double.MAX_VALUE;
			double volume = 0;
			double trades = 0;
			double turnover = 0;
			b.setCode(barList.get(0).getCode());
			b.setOpen(barList.get(0).getOpen());
			b.setLast(barList.get(barList.size()-1).getLast());
			b.setClose(barList.get(barList.size()-1).getClose());
			b.setDate(barList.get(barList.size()-1).getDate());
			for(Bar bar : barList){
				if(high < bar.getHigh())
					high = bar.getHigh();
				if(low > bar.getLow())
					low = bar.getLow();
				volume += bar.getVolume();
				trades += bar.getTrades();
				turnover += bar.getTurnover();
			}
			
			b.setHigh(high);
			b.setLow(low);
			b.setVolume(volume);
			b.setTrades(trades);
			b.setTurnover(turnover);
		}
		return b;
	}
}
